1 module hip.hipaudio.backend.avaudio.clip;
2 
3 version(iOS):
4 public import avaudiobuffer;
5 public import avaudiotypes;
6 import objc.runtime;
7 import avaudiosinknode;
8 import hip.hipaudio.audioclip;
9 import hip.hipaudio.backend.avaudio.player;
10 import hip.api.data.audio;
11 import avaudiosourcenode;
12 import avaudioconverter;
13 
14 
15 extern(C) void tempDeallocator(const(AudioBufferList)* bufferList)
16 {
17     import hip.util.memory;
18     free(cast(void*)bufferList);
19 }
20 
21 AudioBufferList* getAudioBufferList(AudioBuffer buff)
22 {
23     import hip.util.memory;
24     AudioBufferList* ret = cast(AudioBufferList*)malloc(AudioBufferList.sizeof);
25     ret.mNumberBuffers = 1;
26     ret.mBuffers[0] = buff;
27     return ret;
28 }
29 
30 class HipAVAudioClip : HipAudioClip
31 {
32     AVAudioSourceNode source;
33     AVAudioPCMBuffer buffer;
34     AVAudioConverter converter;
35 
36     this(IHipAudioDecoder decoder, HipAudioClipHint hint)
37     {
38         super(decoder, hint); //TODO: Change num channels
39     }
40     override void setBufferData(HipAudioBuffer* buffer, ubyte[] data, uint size = 0)
41     {
42         if(getHint.needsChannelConversion || getHint.needsDecode || getHint.needsResample)
43         {
44             import hip.console.log;
45             import hip.util.conv;
46 
47             static void debugFormat(AVAudioFormat f)
48             {
49                 import hip.console.log;
50                 logln("sampleRate: ", f.sampleRate, " , interleaved: ", f.isInterleaved, " format: ", f.commonFormat );
51             }
52             static void debugBuffer(AVAudioPCMBuffer b)
53             {
54                 import hip.console.log;
55                 logln("frameLength: ", b.frameLength, " , frameCapacity: ", b.frameCapacity, " stride: ", b.stride);
56             }
57             
58             AVAudioFormat rawFormat = HipAVAudioPlayer.fromConfig(decoder.getAudioConfig);
59             converter = AVAudioConverter.alloc.initFromFormat(
60                 rawFormat,
61                 HipAVAudioPlayer.fromConfig(HipAVAudioPlayer.getAudioConfig)
62             );
63 
64             AudioBufferList* list = getAudioBufferList(AudioBuffer(decoder.getClipChannels, 
65                 cast(uint)getClipSize, getClipData.ptr)
66             );
67 
68             AVAudioPCMBuffer temp = AVAudioPCMBuffer.alloc.initWithPCMFormat(
69                 rawFormat, list, &tempDeallocator
70             );
71 
72 
73             NSError err;
74             auto convFn = block((AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus* outStatus)
75             {
76                 if(temp.frameLength > 0)
77                 {
78                     *outStatus = AVAudioConverterInputStatus._HaveData;
79                     return cast(AVAudioBuffer)temp;
80                 }
81                 else
82                 {
83                     *outStatus = AVAudioConverterInputStatus._NoDataNow;
84                     return null;
85                 }
86             });
87 
88             converter.convertToBuffer(cast(AVAudioBuffer)buffer.avaudio, &err, &convFn);
89 
90             if(err)
91             {
92                 import hip.error.handler;
93                 ErrorHandler.assertExit(false, "Could not convert buffer: "~err.toString);
94             }
95         }
96         else
97         {
98             AVAudioFormat rawFormat = HipAVAudioPlayer.fromConfig(decoder.getAudioConfig);
99             AudioBufferList list = AudioBufferList(1, AudioBuffer(decoder.getClipChannels, 
100                 cast(uint)getClipSize, getClipData.ptr)
101             );
102             this.buffer = AVAudioPCMBuffer.alloc.initWithPCMFormat(
103                 rawFormat, &list, &tempDeallocator
104             );
105         }
106         
107     }
108     
109     ///Nothing to do
110     override protected void onUpdateStream(ubyte[] data, uint decodedSize){}
111 
112     ///Wraps an AVAudioBuffer buffer    
113     override protected HipAudioBufferWrapper createBuffer(ubyte[] data)
114     {
115         this.buffer = AVAudioPCMBuffer.alloc.initWithPCMFormat(HipAVAudioPlayer.fromConfig(HipAVAudioPlayer.getAudioConfig), cast(uint)data.length);
116         HipAudioBufferWrapper ret; // TODO: implement
117         ret.buffer.avaudio = buffer;
118         return ret;
119     }
120 
121 
122     ///Calls XAudio2.9 specific buffer destroy
123     override protected void destroyBuffer(HipAudioBuffer* buffer)
124     {
125         
126     }
127 }